package com.timguan.render.dataprocessor.processor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.timguan.render.api.entity.cms.CMSDataProcessorParamInfo;
import com.timguan.render.api.entity.dataprocessor.ItemGroupByDay;
import com.timguan.render.api.entity.dataprocessor.ItemGroupByDay.ItemGroupByHour;
import com.timguan.render.dataapi.api.ICmsDataManager;
import com.timguan.render.dataapi.domain.CmsDataDO;
import com.timguan.render.dataprocessor.filter.TimeVaildFilter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 秒杀商品处理逻辑
 * Created by guankaiqiang on 2015/3/21.
 */
public class SpikeItemListProcessor extends DataProcessor {
    private static final Logger logger = LoggerFactory.getLogger(SpikeItemListProcessor.class);
    private static final FastDateFormat DAY_FMT = FastDateFormat.getInstance("MM月dd日", TimeZone.getDefault(),
            Locale.getDefault());
    private static final FastDateFormat HOUR_FMT = FastDateFormat.getInstance("HH:mm", TimeZone.getDefault(),
            Locale.getDefault());
    private static final FastDateFormat DAY_TIME_FMT = FastDateFormat.getInstance("yyyyMMdd000000", TimeZone.getDefault(),
            Locale.getDefault());
    private static final FastDateFormat HOUR_TIME_FMT = FastDateFormat.getInstance("yyyyMMddHHmm00", TimeZone.getDefault(),
            Locale.getDefault());
    private static final String MIN = "20150101000000";
    private static final String MAX = "21150101000000";
    private static final String TODAY_FRONT_DESC = "今天";
    @Autowired
    private ICmsDataManager cmsDataManagerImpl;
    @Autowired
    private TimeVaildFilter timeVaildFilter;

    static class StartTimeComparator implements Comparator<CmsDataDO> {
        private static final Date DEFAULT_DATE = new Date(0);

        @Override
        public int compare(CmsDataDO o1, CmsDataDO o2) {
            Date leftStartTime = DEFAULT_DATE, rightStartTime = DEFAULT_DATE;
            if (o1.getStarttime() != null) {
                leftStartTime = o1.getStarttime();
            }
            if (o2.getEndtime() != null) {
                rightStartTime = o2.getStarttime();
            }
            if (leftStartTime.after(rightStartTime)) {
                return 1;
            } else if (leftStartTime.before(rightStartTime)) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    private static final Comparator<CmsDataDO> STARTTIME_COMPARATOR = new StartTimeComparator();


    private static String getDayLineFrontDesc(Date dateTime) {
        Calendar today = Calendar.getInstance();//今天
        today.set(Calendar.HOUR_OF_DAY, 0);
        today.set(Calendar.MINUTE, 0);
        today.set(Calendar.SECOND, 0);
        today.set(Calendar.MILLISECOND, 0);
        long todayMillis = today.getTimeInMillis();
        Calendar tomorrow = Calendar.getInstance();    //后天
        tomorrow.add(Calendar.DAY_OF_MONTH, 1);
        tomorrow.set(Calendar.HOUR_OF_DAY, 0);
        tomorrow.set(Calendar.MINUTE, 0);
        tomorrow.set(Calendar.SECOND, 0);
        tomorrow.set(Calendar.MILLISECOND, 0);
        long tomorrowMillis = tomorrow.getTimeInMillis();
        long currentMillis = dateTime.getTime();
        if (todayMillis <= currentMillis && currentMillis < tomorrowMillis) {
            return TODAY_FRONT_DESC;
        } else {
            return DAY_FMT.format(dateTime);
        }
    }

    /**
     * 根据时间轴组织元数据
     *
     * @param wrapper
     * @param cmsDataDOs
     * @param advance    提前量
     * @return
     */
    private Map<String, ItemGroupByDay> groupByTimeLine(CommonParametersWrapper wrapper, List<CmsDataDO> cmsDataDOs, long advance) {
        Map<String, ItemGroupByDay> itemGroupByDayMap = null;
        if (cmsDataDOs != null && cmsDataDOs.size() > 0) {
            //保持原有排序
            Integer id = Constants.SPM_START;
            itemGroupByDayMap = new LinkedHashMap<String, ItemGroupByDay>();
            for (CmsDataDO data : cmsDataDOs) {
                if (data.getStarttime() != null && StringUtils.isNotBlank(data.getPropertyValue())) {
                    Map<String, String> dataEntry = JSON.parseObject(data.getPropertyValue(), new TypeReference<Map<String, String>>() {
                    });
                    if (dataEntry != null) {
                        {
                            //设置spm值
                            dataEntry = setSpm(wrapper, dataEntry, id);
                            //设置数据TYPE
                            dataEntry = setDataTypeAndActionType(dataEntry);
                            id++;
                        }
                        String dayLine = DAY_TIME_FMT.format(data.getStarttime().getTime());
                        ItemGroupByDay itemGroupByDay = itemGroupByDayMap.get(dayLine);
                        if (itemGroupByDay == null) {
                            itemGroupByDay = new ItemGroupByDay(dayLine,
                                    getDayLineFrontDesc(data.getStarttime()), new ArrayList<ItemGroupByHour>());
                        }
                        String hourStart = HOUR_TIME_FMT.format(data.getStarttime().getTime() - advance);
                        ItemGroupByHour itemGroupByHour = itemGroupByDay.findItemGroupByHourStart(hourStart);
                        if (itemGroupByHour == null) {//初始化
                            itemGroupByHour = new ItemGroupByHour(hourStart,
                                    HOUR_FMT.format(data.getStarttime()), new ArrayList<Object>());
                            itemGroupByDay.getItemGroupByHours().add(itemGroupByHour);
                        }
                        //添加商品
                        itemGroupByHour.getItems().add(dataEntry);
                        itemGroupByDayMap.put(dayLine, itemGroupByDay);
                    }
                }
            }
        }
        return itemGroupByDayMap;
    }

    /**
     * 给小时线设置结束时间
     *
     * @param itemGroupByDay
     */
    private void setHourLineEnd(ItemGroupByDay itemGroupByDay) {
        int index = 0;
        List<ItemGroupByHour> itemGroupByHours = itemGroupByDay.getItemGroupByHours();
        for (ItemGroupByHour itemGroupByHour : itemGroupByHours) {
            if (itemGroupByHours.size() == 1) {
                itemGroupByHour.setHourLineStart(MIN);
                itemGroupByHour.setHourLineEnd(MAX);
            } else {
                if (index == 0) {
                    itemGroupByHour.setHourLineStart(MIN);
                    itemGroupByHour.setHourLineEnd(itemGroupByHours.get(index + 1).getHourLineStart());
                } else if (index == itemGroupByHours.size() - 1) {
                    itemGroupByHour.setHourLineEnd(MAX);
                } else {
                    itemGroupByHour.setHourLineEnd(itemGroupByHours.get(index + 1).getHourLineStart());
                }
            }
            index++;
        }
    }

    /**
     * 设置timeLine结束时间
     *
     * @param itemGroupByDayMap
     */
    private void setTimeLineEnd(Map<String, ItemGroupByDay> itemGroupByDayMap) {
        int index = 0;
        List<ItemGroupByDay> itemGroupByDays = new ArrayList<ItemGroupByDay>(itemGroupByDayMap.values());
        for (ItemGroupByDay itemGroupByDay : itemGroupByDays) {
            if (itemGroupByDays.size() == 1) {
                itemGroupByDay.setDayLineStart(MIN);
                itemGroupByDay.setDayLineEnd(MAX);
            } else {
                if (index == 0) {
                    itemGroupByDay.setDayLineStart(MIN);
                    itemGroupByDay.setDayLineEnd(itemGroupByDays.get(index + 1).getDayLineStart());
                } else if (index == itemGroupByDayMap.values().size() - 1) {
                    itemGroupByDay.setDayLineEnd(MAX);
                } else {
                    itemGroupByDay.setDayLineEnd(itemGroupByDays.get(index + 1).getDayLineStart());
                }
            }
            setHourLineEnd(itemGroupByDay);
            index++;
        }
    }

    /**
     * 查询有效的秒杀信息
     *
     * @param listId
     * @return
     */
    public List<CmsDataDO> getCmsDataList(int listId) {
        List<CmsDataDO> cmsDataDOs = cmsDataManagerImpl.selectByListId(listId);
        Map<String, String> filterParams = new HashMap<String, String>();
        //当日00:00:00
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        filterParams.put(START_DISPLAY_TIME, String.valueOf(calendar.getTime().getTime()));
        calendar.add(Calendar.DAY_OF_MONTH, 5);
        filterParams.put(END_DISPLAY_TIME, String.valueOf(calendar.getTime().getTime()));
        cmsDataDOs = dataFilterChain.doFilter(cmsDataDOs, filterParams);
        return cmsDataDOs;
    }

    protected List<Object> execute(CommonParametersWrapper wrapper, Map<String, String> params) {
        List<Object> dataList = null;
        if (params != null && params.get(PROCESSOR_PARAM_DATALISTID) != null) {
            int listId = Integer.valueOf(params.get(PROCESSOR_PARAM_DATALISTID));
            //1.秒杀商品数据列表
            List<CmsDataDO> cmsDataDOs = getCmsDataList(listId);
            //2.按照开始时间倒叙排序
            Collections.sort(cmsDataDOs, STARTTIME_COMPARATOR);
            //2.秒杀商品分组
            long advance = StringUtils.isNotBlank(params.get(ADVANCE)) ? Long.parseLong(params.get(ADVANCE)) * 1000 : 10 * 60 * 1000;
            Map<String, ItemGroupByDay> itemGroupByDayMap = groupByTimeLine(wrapper, cmsDataDOs, advance);
            //3.设置结束时间
            if (itemGroupByDayMap != null && itemGroupByDayMap.size() != 0) {
                setTimeLineEnd(itemGroupByDayMap);
                dataList = new ArrayList<Object>(itemGroupByDayMap.values());
            }
        }
        return dataList;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //使用时需要创建数据列表
        needCreateDatalistWhenUsed = true;
        description = "秒杀";
        paramInfos = new CMSDataProcessorParamInfo[1];
        CMSDataProcessorParamInfo dataProcessorParamInfo = new CMSDataProcessorParamInfo();
        dataProcessorParamInfo.setName(ADVANCE);
        dataProcessorParamInfo.setDescription("提前预告(单位s),默认600s");
        paramInfos[0] = dataProcessorParamInfo;
        dataFilterChain.add(timeVaildFilter);
    }
}
